@marmooo/midy 0.0.2 → 0.0.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.
@@ -11,12 +11,6 @@ class MidyGM2 {
11
11
  writable: true,
12
12
  value: 120
13
13
  });
14
- Object.defineProperty(this, "secondsPerBeat", {
15
- enumerable: true,
16
- configurable: true,
17
- writable: true,
18
- value: 0.5
19
- });
20
14
  Object.defineProperty(this, "totalTime", {
21
15
  enumerable: true,
22
16
  configurable: true,
@@ -177,10 +171,10 @@ class MidyGM2 {
177
171
  const response = await fetch(midiUrl);
178
172
  const arrayBuffer = await response.arrayBuffer();
179
173
  const midi = (0, _esm_js_1.parseMidi)(new Uint8Array(arrayBuffer));
174
+ this.ticksPerBeat = midi.header.ticksPerBeat;
180
175
  const midiData = this.extractMidiData(midi);
181
176
  this.instruments = midiData.instruments;
182
177
  this.timeline = midiData.timeline;
183
- this.ticksPerBeat = midi.header.ticksPerBeat;
184
178
  this.totalTime = this.calcTotalTime();
185
179
  }
186
180
  setChannelAudioNodes(audioContext) {
@@ -210,11 +204,14 @@ class MidyGM2 {
210
204
  createChannels(audioContext) {
211
205
  const channels = Array.from({ length: 16 }, () => {
212
206
  return {
213
- ...MidyGM2.channelSettings,
214
- ...MidyGM2.effectSettings,
207
+ ...Midy.channelSettings,
208
+ ...Midy.effectSettings,
215
209
  ...this.setChannelAudioNodes(audioContext),
216
210
  scheduledNotes: new Map(),
217
211
  sostenutoNotes: new Map(),
212
+ channelPressure: {
213
+ ...Midy.controllerDestinationSettings,
214
+ },
218
215
  };
219
216
  });
220
217
  return channels;
@@ -266,28 +263,33 @@ class MidyGM2 {
266
263
  async scheduleTimelineEvents(t, offset, queueIndex) {
267
264
  while (queueIndex < this.timeline.length) {
268
265
  const event = this.timeline[queueIndex];
269
- const time = this.ticksToSecond(event.ticks, this.secondsPerBeat);
270
- if (time > t + this.lookAhead)
266
+ if (event.startTime > t + this.lookAhead)
271
267
  break;
272
268
  switch (event.type) {
273
- case "controller":
274
- this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value);
275
- break;
276
269
  case "noteOn":
277
- await this.scheduleNoteOn(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, time + this.startDelay - offset);
278
- break;
270
+ if (event.velocity !== 0) {
271
+ await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
272
+ break;
273
+ }
274
+ /* falls through */
279
275
  case "noteOff": {
280
- const notePromise = this.scheduleNoteRelease(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, time + this.startDelay - offset);
276
+ const notePromise = this.scheduleNoteRelease(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
281
277
  if (notePromise) {
282
278
  this.notePromises.push(notePromise);
283
279
  }
284
280
  break;
285
281
  }
282
+ case "controller":
283
+ this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value);
284
+ break;
286
285
  case "programChange":
287
286
  this.handleProgramChange(event.channel, event.programNumber);
288
287
  break;
289
- case "setTempo":
290
- this.secondsPerBeat = event.microsecondsPerBeat / 1000000;
288
+ case "channelAftertouch":
289
+ this.handleChannelPressure(event.channel, event.amount);
290
+ break;
291
+ case "pitchBend":
292
+ this.handlePitchBend(event.channel, event.value);
291
293
  break;
292
294
  case "sysEx":
293
295
  this.handleSysEx(event.data);
@@ -297,9 +299,8 @@ class MidyGM2 {
297
299
  return queueIndex;
298
300
  }
299
301
  getQueueIndex(second) {
300
- const ticks = this.secondToTicks(second, this.secondsPerBeat);
301
302
  for (let i = 0; i < this.timeline.length; i++) {
302
- if (ticks <= this.timeline[i].ticks) {
303
+ if (second <= this.timeline[i].startTime) {
303
304
  return i;
304
305
  }
305
306
  }
@@ -441,18 +442,28 @@ class MidyGM2 {
441
442
  timeline.push(event);
442
443
  });
443
444
  });
445
+ const priority = {
446
+ setTempo: 0,
447
+ controller: 1,
448
+ };
444
449
  timeline.sort((a, b) => {
445
- if (a.ticks !== b.ticks) {
450
+ if (a.ticks !== b.ticks)
446
451
  return a.ticks - b.ticks;
447
- }
448
- if (a.type !== "controller" && b.type === "controller") {
449
- return -1;
450
- }
451
- if (a.type === "controller" && b.type !== "controller") {
452
- return 1;
453
- }
454
- return 0;
452
+ return (priority[a.type] || 2) - (priority[b.type] || 2);
455
453
  });
454
+ let prevTempoTime = 0;
455
+ let prevTempoTicks = 0;
456
+ let secondsPerBeat = 0.5;
457
+ for (let i = 0; i < timeline.length; i++) {
458
+ const event = timeline[i];
459
+ const timeFromPrevTempo = this.ticksToSecond(event.ticks - prevTempoTicks, secondsPerBeat);
460
+ event.startTime = prevTempoTime + timeFromPrevTempo;
461
+ if (event.type === "setTempo") {
462
+ prevTempoTime += this.ticksToSecond(event.ticks - prevTempoTicks, secondsPerBeat);
463
+ secondsPerBeat = event.microsecondsPerBeat / 1000000;
464
+ prevTempoTicks = event.ticks;
465
+ }
466
+ }
456
467
  return { instruments, timeline };
457
468
  }
458
469
  stopNotes() {
@@ -504,32 +515,12 @@ class MidyGM2 {
504
515
  }
505
516
  }
506
517
  calcTotalTime() {
507
- const endOfTracks = [];
508
- let prevTicks = 0;
509
518
  let totalTime = 0;
510
- let secondsPerBeat = 0.5;
511
519
  for (let i = 0; i < this.timeline.length; i++) {
512
520
  const event = this.timeline[i];
513
- switch (event.type) {
514
- case "setTempo": {
515
- const durationTicks = event.ticks - prevTicks;
516
- totalTime += this.ticksToSecond(durationTicks, secondsPerBeat);
517
- secondsPerBeat = event.microsecondsPerBeat / 1000000;
518
- prevTicks = event.ticks;
519
- break;
520
- }
521
- case "endOfTrack":
522
- endOfTracks.push(event);
523
- }
524
- }
525
- let maxTicks = 0;
526
- for (let i = 0; i < endOfTracks.length; i++) {
527
- const event = endOfTracks[i];
528
- if (maxTicks < event.ticks)
529
- maxTicks = event.ticks;
521
+ if (totalTime < event.startTime)
522
+ totalTime = event.startTime;
530
523
  }
531
- const durationTicks = maxTicks - prevTicks;
532
- totalTime += this.ticksToSecond(durationTicks, secondsPerBeat);
533
524
  return totalTime;
534
525
  }
535
526
  currentTime() {
@@ -557,11 +548,8 @@ class MidyGM2 {
557
548
  const lfo = new OscillatorNode(audioContext, {
558
549
  frequency: 5,
559
550
  });
560
- const lfoGain = new GainNode(audioContext);
561
- lfo.connect(lfoGain);
562
551
  return {
563
552
  lfo,
564
- lfoGain,
565
553
  };
566
554
  }
567
555
  createReverbEffect(audioContext, options = {}) {
@@ -666,15 +654,19 @@ class MidyGM2 {
666
654
  centToHz(cent) {
667
655
  return 8.176 * Math.pow(2, cent / 1200);
668
656
  }
669
- async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
657
+ calcSemitoneOffset(channel) {
670
658
  const masterTuning = this.masterCoarseTuning + this.masterFineTuning;
671
659
  const channelTuning = channel.coarseTuning + channel.fineTuning;
672
660
  const tuning = masterTuning + channelTuning;
673
- const semitoneOffset = channel.pitchBend * channel.pitchBendRange + tuning;
674
- const playbackRate = noteInfo.playbackRate(noteNumber) *
675
- Math.pow(2, semitoneOffset / 12);
661
+ return channel.pitchBend * channel.pitchBendRange + tuning;
662
+ }
663
+ calcPlaybackRate(noteInfo, noteNumber, semitoneOffset) {
664
+ return noteInfo.playbackRate(noteNumber) * Math.pow(2, semitoneOffset / 12);
665
+ }
666
+ async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
676
667
  const bufferSource = await this.createNoteBufferNode(noteInfo, isSF3);
677
- bufferSource.playbackRate.value = playbackRate;
668
+ const semitoneOffset = this.calcSemitoneOffset(channel);
669
+ bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
678
670
  // volume envelope
679
671
  const gainNode = new GainNode(this.audioContext, {
680
672
  gain: 0,
@@ -693,12 +685,6 @@ class MidyGM2 {
693
685
  .exponentialRampToValueAtTime(attackVolume, volAttack)
694
686
  .setValueAtTime(attackVolume, volHold)
695
687
  .linearRampToValueAtTime(sustainVolume, volDecay);
696
- if (channel.modulation > 0) {
697
- const lfoGain = channel.modulationEffect.lfoGain;
698
- lfoGain.connect(bufferSource.detune);
699
- lfoGain.gain.cancelScheduledValues(startTime + channel.vibratoDelay);
700
- lfoGain.gain.setValueAtTime(channel.modulation, startTime + channel.vibratoDelay);
701
- }
702
688
  // filter envelope
703
689
  const softPedalFactor = 1 -
704
690
  (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
@@ -724,6 +710,19 @@ class MidyGM2 {
724
710
  .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
725
711
  .setValueAtTime(adjustedPeekFreq, modHold)
726
712
  .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
713
+ let lfoGain;
714
+ if (channel.modulation > 0) {
715
+ const vibratoDelay = startTime + channel.vibratoDelay;
716
+ const vibratoAttack = vibratoDelay + 0.1;
717
+ lfoGain = new GainNode(this.audioContext, {
718
+ gain: 0,
719
+ });
720
+ lfoGain.gain
721
+ .setValueAtTime(1e-6, vibratoDelay) // exponentialRampToValueAtTime() requires a non-zero value
722
+ .exponentialRampToValueAtTime(channel.modulation, vibratoAttack);
723
+ channel.modulationEffect.lfo.connect(lfoGain);
724
+ lfoGain.connect(bufferSource.detune);
725
+ }
727
726
  bufferSource.connect(filterNode);
728
727
  filterNode.connect(gainNode);
729
728
  if (this.mono && channel.currentBufferSource) {
@@ -731,7 +730,7 @@ class MidyGM2 {
731
730
  channel.currentBufferSource = bufferSource;
732
731
  }
733
732
  bufferSource.start(startTime, noteInfo.start / noteInfo.sampleRate);
734
- return { bufferSource, gainNode, filterNode };
733
+ return { bufferSource, gainNode, filterNode, lfoGain };
735
734
  }
736
735
  calcBank(channel, channelNumber) {
737
736
  if (channel.bankMSB === 121) {
@@ -753,7 +752,7 @@ class MidyGM2 {
753
752
  const noteInfo = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
754
753
  if (!noteInfo)
755
754
  return;
756
- const { bufferSource, gainNode, filterNode } = await this
755
+ const { bufferSource, gainNode, filterNode, lfoGain } = await this
757
756
  .createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3);
758
757
  this.connectNoteEffects(channel, gainNode);
759
758
  if (channel.sostenutoPedal) {
@@ -767,11 +766,12 @@ class MidyGM2 {
767
766
  }
768
767
  const scheduledNotes = channel.scheduledNotes;
769
768
  const scheduledNote = {
770
- gainNode,
771
- filterNode,
772
769
  bufferSource,
773
- noteNumber,
770
+ filterNode,
771
+ gainNode,
772
+ lfoGain,
774
773
  noteInfo,
774
+ noteNumber,
775
775
  startTime,
776
776
  };
777
777
  if (scheduledNotes.has(noteNumber)) {
@@ -800,7 +800,7 @@ class MidyGM2 {
800
800
  continue;
801
801
  if (targetNote.ending)
802
802
  continue;
803
- const { bufferSource, filterNode, gainNode, noteInfo } = targetNote;
803
+ const { bufferSource, filterNode, gainNode, lfoGain, noteInfo } = targetNote;
804
804
  const velocityRate = (velocity + 127) / 127;
805
805
  const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
806
806
  gainNode.gain.cancelScheduledValues(stopTime);
@@ -822,6 +822,8 @@ class MidyGM2 {
822
822
  bufferSource.disconnect(0);
823
823
  filterNode.disconnect(0);
824
824
  gainNode.disconnect(0);
825
+ if (lfoGain)
826
+ lfoGain.disconnect(0);
825
827
  resolve();
826
828
  };
827
829
  bufferSource.stop(volEndTime);
@@ -832,41 +834,34 @@ class MidyGM2 {
832
834
  const now = this.audioContext.currentTime;
833
835
  return this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now);
834
836
  }
835
- releaseSustainPedal(channelNumber) {
836
- const now = this.audioContext.currentTime;
837
+ releaseSustainPedal(channelNumber, halfVelocity) {
838
+ const velocity = halfVelocity * 2;
837
839
  const channel = this.channels[channelNumber];
840
+ const promises = [];
838
841
  channel.sustainPedal = false;
839
842
  channel.scheduledNotes.forEach((scheduledNotes) => {
840
843
  scheduledNotes.forEach((scheduledNote) => {
841
844
  if (scheduledNote) {
842
- const { bufferSource, gainNode, filterNode, noteInfo } = scheduledNote;
843
- const volEndTime = now + noteInfo.volRelease;
844
- gainNode.gain.cancelScheduledValues(now);
845
- gainNode.gain.linearRampToValueAtTime(0, volEndTime);
846
- const maxFreq = this.audioContext.sampleRate / 2;
847
- const baseFreq = this.centToHz(noteInfo.initialFilterFc);
848
- const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
849
- const modEndTime = now + noteInfo.modRelease;
850
- filterNode.frequency
851
- .cancelScheduledValues(stopTime)
852
- .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
853
- bufferSource.stop(volEndTime);
845
+ const { noteNumber } = scheduledNote;
846
+ const promise = this.releaseNote(channelNumber, noteNumber, velocity);
847
+ promises.push(promise);
854
848
  }
855
849
  });
856
850
  });
851
+ return promises;
857
852
  }
858
- releaseSostenuto(channelNumber) {
859
- const now = this.audioContext.currentTime;
853
+ releaseSostenutoPedal(channelNumber, halfVelocity) {
854
+ const velocity = halfVelocity * 2;
860
855
  const channel = this.channels[channelNumber];
856
+ const promises = [];
861
857
  channel.sostenutoPedal = false;
862
858
  channel.sostenutoNotes.forEach((activeNote) => {
863
- const { gainNode, bufferSource, noteInfo } = activeNote;
864
- const fadeTime = noteInfo.volRelease;
865
- gainNode.gain.cancelScheduledValues(now);
866
- gainNode.gain.linearRampToValueAtTime(0, now + fadeTime);
867
- bufferSource.stop(now + fadeTime);
859
+ const { noteNumber } = activeNote;
860
+ const promise = this.releaseNote(channelNumber, noteNumber, velocity);
861
+ promises.push(promise);
868
862
  });
869
863
  channel.sostenutoNotes.clear();
864
+ return promises;
870
865
  }
871
866
  handleMIDIMessage(statusByte, data1, data2) {
872
867
  const channelNumber = omni ? 0 : statusByte & 0x0F;
@@ -876,8 +871,6 @@ class MidyGM2 {
876
871
  return this.releaseNote(channelNumber, data1, data2);
877
872
  case 0x90:
878
873
  return this.noteOn(channelNumber, data1, data2);
879
- case 0xA0:
880
- return this.handlePolyphonicKeyPressure(channelNumber, data1, data2);
881
874
  case 0xB0:
882
875
  return this.handleControlChange(channelNumber, data1, data2);
883
876
  case 0xC0:
@@ -885,38 +878,48 @@ class MidyGM2 {
885
878
  case 0xD0:
886
879
  return this.handleChannelPressure(channelNumber, data1);
887
880
  case 0xE0:
888
- return this.handlePitchBend(channelNumber, data1, data2);
881
+ return this.handlePitchBendMessage(channelNumber, data1, data2);
889
882
  default:
890
883
  console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
891
884
  }
892
885
  }
893
- handlePolyphonicKeyPressure(channelNumber, noteNumber, pressure) {
894
- const now = this.audioContext.currentTime;
895
- const channel = this.channels[channelNumber];
896
- const scheduledNotes = channel.scheduledNotes.get(noteNumber);
897
- pressure /= 127;
898
- if (scheduledNotes) {
899
- scheduledNotes.forEach((scheduledNote) => {
900
- if (scheduledNote) {
901
- const { initialAttenuation } = scheduledNote.noteInfo;
902
- const gain = this.cbToRatio(-initialAttenuation) * pressure;
903
- scheduledNote.gainNode.gain.cancelScheduledValues(now);
904
- scheduledNote.gainNode.gain.setValueAtTime(gain, now);
905
- }
906
- });
907
- }
908
- }
909
886
  handleProgramChange(channelNumber, program) {
910
887
  const channel = this.channels[channelNumber];
911
888
  channel.bank = channel.bankMSB * 128 + channel.bankLSB;
912
889
  channel.program = program;
913
890
  }
914
891
  handleChannelPressure(channelNumber, pressure) {
915
- this.channels[channelNumber].channelPressure = pressure;
892
+ const now = this.audioContext.currentTime;
893
+ const channel = this.channels[channelNumber];
894
+ pressure /= 64;
895
+ channel.channelPressure = pressure;
896
+ const activeNotes = this.getActiveNotes(channel);
897
+ if (channel.channelPressure.amplitudeControl !== 1) {
898
+ activeNotes.forEach((activeNote) => {
899
+ const gain = activeNote.gainNode.gain.value;
900
+ activeNote.gainNode.gain
901
+ .cancelScheduledValues(now)
902
+ .setValueAtTime(gain * pressure, now);
903
+ });
904
+ }
916
905
  }
917
- handlePitchBend(channelNumber, lsb, msb) {
918
- const pitchBend = (msb * 128 + lsb - 8192) / 8192;
919
- this.channels[channelNumber].pitchBend = pitchBend;
906
+ handlePitchBendMessage(channelNumber, lsb, msb) {
907
+ const pitchBend = msb * 128 + lsb;
908
+ this.handlePitchBend(channelNumber, pitchBend);
909
+ }
910
+ handlePitchBend(channelNumber, pitchBend) {
911
+ const now = this.audioContext.currentTime;
912
+ const channel = this.channels[channelNumber];
913
+ channel.pitchBend = (pitchBend - 8192) / 8192;
914
+ const semitoneOffset = this.calcSemitoneOffset(channel);
915
+ const activeNotes = this.getActiveNotes(channel);
916
+ activeNotes.forEach((activeNote) => {
917
+ const { bufferSource, noteInfo, noteNumber } = activeNote;
918
+ const playbackRate = calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
919
+ bufferSource.playbackRate
920
+ .cancelScheduledValues(now)
921
+ .setValueAtTime(playbackRate * pressure, now);
922
+ });
920
923
  }
921
924
  handleControlChange(channelNumber, controller, value) {
922
925
  switch (controller) {
@@ -976,13 +979,9 @@ class MidyGM2 {
976
979
  this.channels[channelNumber].bankMSB = msb;
977
980
  }
978
981
  setModulation(channelNumber, modulation) {
979
- const now = this.audioContext.currentTime;
980
982
  const channel = this.channels[channelNumber];
981
- channel.modulation = (modulation * 100 / 127) *
982
- channel.modulationDepthRange;
983
- const lfoGain = channel.modulationEffect.lfoGain;
984
- lfoGain.gain.cancelScheduledValues(now);
985
- lfoGain.gain.setValueAtTime(channel.modulation, now);
983
+ channel.modulation = (modulation / 127) *
984
+ (channel.modulationDepthRange * 100);
986
985
  }
987
986
  setPortamentoTime(channelNumber, portamentoTime) {
988
987
  this.channels[channelNumber].portamentoTime = portamentoTime / 127;
@@ -1017,7 +1016,7 @@ class MidyGM2 {
1017
1016
  const isOn = value >= 64;
1018
1017
  this.channels[channelNumber].sustainPedal = isOn;
1019
1018
  if (!isOn) {
1020
- this.releaseSustainPedal(channelNumber);
1019
+ this.releaseSustainPedal(channelNumber, value);
1021
1020
  }
1022
1021
  }
1023
1022
  setPortamento(channelNumber, value) {
@@ -1046,11 +1045,13 @@ class MidyGM2 {
1046
1045
  const activeNotes = this.getActiveNotes(channel);
1047
1046
  channel.sostenutoNotes = new Map(activeNotes);
1048
1047
  }
1048
+ else {
1049
+ this.releaseSostenutoPedal(channelNumber, value);
1050
+ }
1049
1051
  }
1050
1052
  setSoftPedal(channelNumber, softPedal) {
1051
1053
  const channel = this.channels[channelNumber];
1052
1054
  channel.softPedal = softPedal / 127;
1053
- this.updateChannelGain(channel);
1054
1055
  }
1055
1056
  setRPNMSB(channelNumber, value) {
1056
1057
  this.channels[channelNumber].rpnMSB = value;
@@ -1191,10 +1192,10 @@ class MidyGM2 {
1191
1192
  switch (data[3]) {
1192
1193
  // case 1:
1193
1194
  // // TODO
1194
- // return this.handleChannelPressure();
1195
+ // return this.setChannelPressure();
1195
1196
  // case 3:
1196
1197
  // // TODO
1197
- // return this.handleControlChange();
1198
+ // return this.setControlChange();
1198
1199
  default:
1199
1200
  console.warn(`Unsupported Exclusive Message ${data}`);
1200
1201
  }
@@ -1213,20 +1214,25 @@ class MidyGM2 {
1213
1214
  }
1214
1215
  }
1215
1216
  handleMasterVolumeSysEx(data) {
1216
- const volume = (data[5] * 128 + data[4] - 8192) / 8192;
1217
+ const volume = (data[5] * 128 + data[4]) / 16383;
1217
1218
  this.handleMasterVolume(volume);
1218
1219
  }
1219
1220
  handleMasterVolume(volume) {
1220
- const now = this.audioContext.currentTime;
1221
- this.masterGain.gain.cancelScheduledValues(now);
1222
- this.masterGain.gain.setValueAtTime(volume * volume, now);
1221
+ if (volume < 0 && 1 < volume) {
1222
+ console.error("Master Volume is out of range");
1223
+ }
1224
+ else {
1225
+ const now = this.audioContext.currentTime;
1226
+ this.masterGain.gain.cancelScheduledValues(now);
1227
+ this.masterGain.gain.setValueAtTime(volume * volume, now);
1228
+ }
1223
1229
  }
1224
1230
  handleMasterFineTuningSysEx(data) {
1225
1231
  const fineTuning = (data[5] * 128 + data[4] - 8192) / 8192;
1226
1232
  this.handleMasterFineTuning(fineTuning);
1227
1233
  }
1228
1234
  handleMasterFineTuning(fineTuning) {
1229
- if (fineTuning < 0 && 1 < fineTuning) {
1235
+ if (fineTuning < -1 && 1 < fineTuning) {
1230
1236
  console.error("Master Fine Tuning value is out of range");
1231
1237
  }
1232
1238
  else {
@@ -1277,7 +1283,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
1277
1283
  writable: true,
1278
1284
  value: {
1279
1285
  currentBufferSource: null,
1280
- volume: 1,
1286
+ volume: 100 / 127,
1281
1287
  pan: 0,
1282
1288
  portamentoTime: 0,
1283
1289
  reverb: 0,
@@ -1294,7 +1300,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
1294
1300
  pitchBend: 0,
1295
1301
  fineTuning: 0,
1296
1302
  coarseTuning: 0,
1297
- modulationDepthRange: 2,
1303
+ modulationDepthRange: 0.5,
1298
1304
  }
1299
1305
  });
1300
1306
  Object.defineProperty(MidyGM2, "effectSettings", {
@@ -1314,3 +1320,16 @@ Object.defineProperty(MidyGM2, "effectSettings", {
1314
1320
  pitchBendRange: 2,
1315
1321
  }
1316
1322
  });
1323
+ Object.defineProperty(MidyGM2, "controllerDestinationSettings", {
1324
+ enumerable: true,
1325
+ configurable: true,
1326
+ writable: true,
1327
+ value: {
1328
+ pitchControl: 0,
1329
+ filterCutoffControl: 0,
1330
+ amplitudeControl: 1,
1331
+ lfoPitchDepth: 0,
1332
+ lfoFilterDepth: 0,
1333
+ lfoAmplitudeDepth: 0,
1334
+ }
1335
+ });
@@ -22,7 +22,6 @@ export class MidyGMLite {
22
22
  };
23
23
  constructor(audioContext: any);
24
24
  ticksPerBeat: number;
25
- secondsPerBeat: number;
26
25
  totalTime: number;
27
26
  noteCheckInterval: number;
28
27
  lookAhead: number;
@@ -48,7 +47,6 @@ export class MidyGMLite {
48
47
  pannerNode: any;
49
48
  modulationEffect: {
50
49
  lfo: any;
51
- lfoGain: any;
52
50
  };
53
51
  expression: number;
54
52
  modulation: number;
@@ -77,7 +75,6 @@ export class MidyGMLite {
77
75
  pannerNode: any;
78
76
  modulationEffect: {
79
77
  lfo: any;
80
- lfoGain: any;
81
78
  };
82
79
  };
83
80
  createChannels(audioContext: any): {
@@ -87,7 +84,6 @@ export class MidyGMLite {
87
84
  pannerNode: any;
88
85
  modulationEffect: {
89
86
  lfo: any;
90
- lfoGain: any;
91
87
  };
92
88
  expression: number;
93
89
  modulation: number;
@@ -131,31 +127,27 @@ export class MidyGMLite {
131
127
  getActiveChannelNotes(scheduledNotes: any): any;
132
128
  createModulationEffect(audioContext: any): {
133
129
  lfo: any;
134
- lfoGain: any;
135
- };
136
- createReverbEffect(audioContext: any, options?: {}): {
137
- convolverNode: any;
138
- dryGain: any;
139
- wetGain: any;
140
130
  };
141
131
  connectNoteEffects(channel: any, gainNode: any): void;
142
132
  cbToRatio(cb: any): number;
143
133
  centToHz(cent: any): number;
134
+ calcSemitoneOffset(channel: any): any;
135
+ calcPlaybackRate(noteInfo: any, noteNumber: any, semitoneOffset: any): number;
144
136
  createNoteAudioChain(channel: any, noteInfo: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<{
145
137
  bufferSource: any;
146
138
  gainNode: any;
147
139
  filterNode: any;
140
+ lfoGain: any;
148
141
  }>;
149
142
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
150
143
  noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
151
144
  scheduleNoteRelease(channelNumber: any, noteNumber: any, velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
152
145
  releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
153
- releaseSustainPedal(channelNumber: any): void;
146
+ releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
154
147
  handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
155
- handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
156
148
  handleProgramChange(channelNumber: any, program: any): void;
157
- handleChannelPressure(channelNumber: any, pressure: any): void;
158
- handlePitchBend(channelNumber: any, lsb: any, msb: any): void;
149
+ handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
150
+ handlePitchBend(channelNumber: any, pitchBend: any): void;
159
151
  handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
160
152
  setModulation(channelNumber: any, modulation: any): void;
161
153
  setVolume(channelNumber: any, volume: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAMA;IAoBE;;;;;;;;;;;;MAYE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAhDD,qBAAmB;IACnB,uBAAqB;IACrB,kBAAc;IACd,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;IA0BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA0DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAuEC;IAED,kGAsCC;IAED,0EAGC;IAED,sIA0CC;IAED,0FAGC;IAED,8CAuBC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAQC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAcC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAMA;IAmBE;;;;;;;;;;;;MAYE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA/CD,qBAAmB;IACnB,kBAAc;IACd,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;IA0BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAyEC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;MAOC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED,sCAEC;IAED,8EAEC;IAED;;;;;OA8EC;IAED,kGAuCC;IAED,0EAGC;IAED,sIA4CC;IAED,0FAGC;IAED,kEAeC;IAED,wFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,0DAiBC;IAED,mFA+BC;IAED,yDAIC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAcC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}