@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.
package/esm/midy-GM2.js CHANGED
@@ -8,12 +8,6 @@ export class MidyGM2 {
8
8
  writable: true,
9
9
  value: 120
10
10
  });
11
- Object.defineProperty(this, "secondsPerBeat", {
12
- enumerable: true,
13
- configurable: true,
14
- writable: true,
15
- value: 0.5
16
- });
17
11
  Object.defineProperty(this, "totalTime", {
18
12
  enumerable: true,
19
13
  configurable: true,
@@ -174,10 +168,10 @@ export class MidyGM2 {
174
168
  const response = await fetch(midiUrl);
175
169
  const arrayBuffer = await response.arrayBuffer();
176
170
  const midi = parseMidi(new Uint8Array(arrayBuffer));
171
+ this.ticksPerBeat = midi.header.ticksPerBeat;
177
172
  const midiData = this.extractMidiData(midi);
178
173
  this.instruments = midiData.instruments;
179
174
  this.timeline = midiData.timeline;
180
- this.ticksPerBeat = midi.header.ticksPerBeat;
181
175
  this.totalTime = this.calcTotalTime();
182
176
  }
183
177
  setChannelAudioNodes(audioContext) {
@@ -207,11 +201,14 @@ export class MidyGM2 {
207
201
  createChannels(audioContext) {
208
202
  const channels = Array.from({ length: 16 }, () => {
209
203
  return {
210
- ...MidyGM2.channelSettings,
211
- ...MidyGM2.effectSettings,
204
+ ...Midy.channelSettings,
205
+ ...Midy.effectSettings,
212
206
  ...this.setChannelAudioNodes(audioContext),
213
207
  scheduledNotes: new Map(),
214
208
  sostenutoNotes: new Map(),
209
+ channelPressure: {
210
+ ...Midy.controllerDestinationSettings,
211
+ },
215
212
  };
216
213
  });
217
214
  return channels;
@@ -263,28 +260,33 @@ export class MidyGM2 {
263
260
  async scheduleTimelineEvents(t, offset, queueIndex) {
264
261
  while (queueIndex < this.timeline.length) {
265
262
  const event = this.timeline[queueIndex];
266
- const time = this.ticksToSecond(event.ticks, this.secondsPerBeat);
267
- if (time > t + this.lookAhead)
263
+ if (event.startTime > t + this.lookAhead)
268
264
  break;
269
265
  switch (event.type) {
270
- case "controller":
271
- this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value);
272
- break;
273
266
  case "noteOn":
274
- await this.scheduleNoteOn(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, time + this.startDelay - offset);
275
- break;
267
+ if (event.velocity !== 0) {
268
+ await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
269
+ break;
270
+ }
271
+ /* falls through */
276
272
  case "noteOff": {
277
- const notePromise = this.scheduleNoteRelease(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, time + this.startDelay - offset);
273
+ const notePromise = this.scheduleNoteRelease(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset);
278
274
  if (notePromise) {
279
275
  this.notePromises.push(notePromise);
280
276
  }
281
277
  break;
282
278
  }
279
+ case "controller":
280
+ this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value);
281
+ break;
283
282
  case "programChange":
284
283
  this.handleProgramChange(event.channel, event.programNumber);
285
284
  break;
286
- case "setTempo":
287
- this.secondsPerBeat = event.microsecondsPerBeat / 1000000;
285
+ case "channelAftertouch":
286
+ this.handleChannelPressure(event.channel, event.amount);
287
+ break;
288
+ case "pitchBend":
289
+ this.handlePitchBend(event.channel, event.value);
288
290
  break;
289
291
  case "sysEx":
290
292
  this.handleSysEx(event.data);
@@ -294,9 +296,8 @@ export class MidyGM2 {
294
296
  return queueIndex;
295
297
  }
296
298
  getQueueIndex(second) {
297
- const ticks = this.secondToTicks(second, this.secondsPerBeat);
298
299
  for (let i = 0; i < this.timeline.length; i++) {
299
- if (ticks <= this.timeline[i].ticks) {
300
+ if (second <= this.timeline[i].startTime) {
300
301
  return i;
301
302
  }
302
303
  }
@@ -438,18 +439,28 @@ export class MidyGM2 {
438
439
  timeline.push(event);
439
440
  });
440
441
  });
442
+ const priority = {
443
+ setTempo: 0,
444
+ controller: 1,
445
+ };
441
446
  timeline.sort((a, b) => {
442
- if (a.ticks !== b.ticks) {
447
+ if (a.ticks !== b.ticks)
443
448
  return a.ticks - b.ticks;
444
- }
445
- if (a.type !== "controller" && b.type === "controller") {
446
- return -1;
447
- }
448
- if (a.type === "controller" && b.type !== "controller") {
449
- return 1;
450
- }
451
- return 0;
449
+ return (priority[a.type] || 2) - (priority[b.type] || 2);
452
450
  });
451
+ let prevTempoTime = 0;
452
+ let prevTempoTicks = 0;
453
+ let secondsPerBeat = 0.5;
454
+ for (let i = 0; i < timeline.length; i++) {
455
+ const event = timeline[i];
456
+ const timeFromPrevTempo = this.ticksToSecond(event.ticks - prevTempoTicks, secondsPerBeat);
457
+ event.startTime = prevTempoTime + timeFromPrevTempo;
458
+ if (event.type === "setTempo") {
459
+ prevTempoTime += this.ticksToSecond(event.ticks - prevTempoTicks, secondsPerBeat);
460
+ secondsPerBeat = event.microsecondsPerBeat / 1000000;
461
+ prevTempoTicks = event.ticks;
462
+ }
463
+ }
453
464
  return { instruments, timeline };
454
465
  }
455
466
  stopNotes() {
@@ -501,32 +512,12 @@ export class MidyGM2 {
501
512
  }
502
513
  }
503
514
  calcTotalTime() {
504
- const endOfTracks = [];
505
- let prevTicks = 0;
506
515
  let totalTime = 0;
507
- let secondsPerBeat = 0.5;
508
516
  for (let i = 0; i < this.timeline.length; i++) {
509
517
  const event = this.timeline[i];
510
- switch (event.type) {
511
- case "setTempo": {
512
- const durationTicks = event.ticks - prevTicks;
513
- totalTime += this.ticksToSecond(durationTicks, secondsPerBeat);
514
- secondsPerBeat = event.microsecondsPerBeat / 1000000;
515
- prevTicks = event.ticks;
516
- break;
517
- }
518
- case "endOfTrack":
519
- endOfTracks.push(event);
520
- }
521
- }
522
- let maxTicks = 0;
523
- for (let i = 0; i < endOfTracks.length; i++) {
524
- const event = endOfTracks[i];
525
- if (maxTicks < event.ticks)
526
- maxTicks = event.ticks;
518
+ if (totalTime < event.startTime)
519
+ totalTime = event.startTime;
527
520
  }
528
- const durationTicks = maxTicks - prevTicks;
529
- totalTime += this.ticksToSecond(durationTicks, secondsPerBeat);
530
521
  return totalTime;
531
522
  }
532
523
  currentTime() {
@@ -554,11 +545,8 @@ export class MidyGM2 {
554
545
  const lfo = new OscillatorNode(audioContext, {
555
546
  frequency: 5,
556
547
  });
557
- const lfoGain = new GainNode(audioContext);
558
- lfo.connect(lfoGain);
559
548
  return {
560
549
  lfo,
561
- lfoGain,
562
550
  };
563
551
  }
564
552
  createReverbEffect(audioContext, options = {}) {
@@ -663,15 +651,19 @@ export class MidyGM2 {
663
651
  centToHz(cent) {
664
652
  return 8.176 * Math.pow(2, cent / 1200);
665
653
  }
666
- async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
654
+ calcSemitoneOffset(channel) {
667
655
  const masterTuning = this.masterCoarseTuning + this.masterFineTuning;
668
656
  const channelTuning = channel.coarseTuning + channel.fineTuning;
669
657
  const tuning = masterTuning + channelTuning;
670
- const semitoneOffset = channel.pitchBend * channel.pitchBendRange + tuning;
671
- const playbackRate = noteInfo.playbackRate(noteNumber) *
672
- Math.pow(2, semitoneOffset / 12);
658
+ return channel.pitchBend * channel.pitchBendRange + tuning;
659
+ }
660
+ calcPlaybackRate(noteInfo, noteNumber, semitoneOffset) {
661
+ return noteInfo.playbackRate(noteNumber) * Math.pow(2, semitoneOffset / 12);
662
+ }
663
+ async createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3) {
673
664
  const bufferSource = await this.createNoteBufferNode(noteInfo, isSF3);
674
- bufferSource.playbackRate.value = playbackRate;
665
+ const semitoneOffset = this.calcSemitoneOffset(channel);
666
+ bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
675
667
  // volume envelope
676
668
  const gainNode = new GainNode(this.audioContext, {
677
669
  gain: 0,
@@ -690,12 +682,6 @@ export class MidyGM2 {
690
682
  .exponentialRampToValueAtTime(attackVolume, volAttack)
691
683
  .setValueAtTime(attackVolume, volHold)
692
684
  .linearRampToValueAtTime(sustainVolume, volDecay);
693
- if (channel.modulation > 0) {
694
- const lfoGain = channel.modulationEffect.lfoGain;
695
- lfoGain.connect(bufferSource.detune);
696
- lfoGain.gain.cancelScheduledValues(startTime + channel.vibratoDelay);
697
- lfoGain.gain.setValueAtTime(channel.modulation, startTime + channel.vibratoDelay);
698
- }
699
685
  // filter envelope
700
686
  const softPedalFactor = 1 -
701
687
  (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
@@ -721,6 +707,19 @@ export class MidyGM2 {
721
707
  .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
722
708
  .setValueAtTime(adjustedPeekFreq, modHold)
723
709
  .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
710
+ let lfoGain;
711
+ if (channel.modulation > 0) {
712
+ const vibratoDelay = startTime + channel.vibratoDelay;
713
+ const vibratoAttack = vibratoDelay + 0.1;
714
+ lfoGain = new GainNode(this.audioContext, {
715
+ gain: 0,
716
+ });
717
+ lfoGain.gain
718
+ .setValueAtTime(1e-6, vibratoDelay) // exponentialRampToValueAtTime() requires a non-zero value
719
+ .exponentialRampToValueAtTime(channel.modulation, vibratoAttack);
720
+ channel.modulationEffect.lfo.connect(lfoGain);
721
+ lfoGain.connect(bufferSource.detune);
722
+ }
724
723
  bufferSource.connect(filterNode);
725
724
  filterNode.connect(gainNode);
726
725
  if (this.mono && channel.currentBufferSource) {
@@ -728,7 +727,7 @@ export class MidyGM2 {
728
727
  channel.currentBufferSource = bufferSource;
729
728
  }
730
729
  bufferSource.start(startTime, noteInfo.start / noteInfo.sampleRate);
731
- return { bufferSource, gainNode, filterNode };
730
+ return { bufferSource, gainNode, filterNode, lfoGain };
732
731
  }
733
732
  calcBank(channel, channelNumber) {
734
733
  if (channel.bankMSB === 121) {
@@ -750,7 +749,7 @@ export class MidyGM2 {
750
749
  const noteInfo = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
751
750
  if (!noteInfo)
752
751
  return;
753
- const { bufferSource, gainNode, filterNode } = await this
752
+ const { bufferSource, gainNode, filterNode, lfoGain } = await this
754
753
  .createNoteAudioChain(channel, noteInfo, noteNumber, velocity, startTime, isSF3);
755
754
  this.connectNoteEffects(channel, gainNode);
756
755
  if (channel.sostenutoPedal) {
@@ -764,11 +763,12 @@ export class MidyGM2 {
764
763
  }
765
764
  const scheduledNotes = channel.scheduledNotes;
766
765
  const scheduledNote = {
767
- gainNode,
768
- filterNode,
769
766
  bufferSource,
770
- noteNumber,
767
+ filterNode,
768
+ gainNode,
769
+ lfoGain,
771
770
  noteInfo,
771
+ noteNumber,
772
772
  startTime,
773
773
  };
774
774
  if (scheduledNotes.has(noteNumber)) {
@@ -797,7 +797,7 @@ export class MidyGM2 {
797
797
  continue;
798
798
  if (targetNote.ending)
799
799
  continue;
800
- const { bufferSource, filterNode, gainNode, noteInfo } = targetNote;
800
+ const { bufferSource, filterNode, gainNode, lfoGain, noteInfo } = targetNote;
801
801
  const velocityRate = (velocity + 127) / 127;
802
802
  const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
803
803
  gainNode.gain.cancelScheduledValues(stopTime);
@@ -819,6 +819,8 @@ export class MidyGM2 {
819
819
  bufferSource.disconnect(0);
820
820
  filterNode.disconnect(0);
821
821
  gainNode.disconnect(0);
822
+ if (lfoGain)
823
+ lfoGain.disconnect(0);
822
824
  resolve();
823
825
  };
824
826
  bufferSource.stop(volEndTime);
@@ -829,41 +831,34 @@ export class MidyGM2 {
829
831
  const now = this.audioContext.currentTime;
830
832
  return this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now);
831
833
  }
832
- releaseSustainPedal(channelNumber) {
833
- const now = this.audioContext.currentTime;
834
+ releaseSustainPedal(channelNumber, halfVelocity) {
835
+ const velocity = halfVelocity * 2;
834
836
  const channel = this.channels[channelNumber];
837
+ const promises = [];
835
838
  channel.sustainPedal = false;
836
839
  channel.scheduledNotes.forEach((scheduledNotes) => {
837
840
  scheduledNotes.forEach((scheduledNote) => {
838
841
  if (scheduledNote) {
839
- const { bufferSource, gainNode, filterNode, noteInfo } = scheduledNote;
840
- const volEndTime = now + noteInfo.volRelease;
841
- gainNode.gain.cancelScheduledValues(now);
842
- gainNode.gain.linearRampToValueAtTime(0, volEndTime);
843
- const maxFreq = this.audioContext.sampleRate / 2;
844
- const baseFreq = this.centToHz(noteInfo.initialFilterFc);
845
- const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
846
- const modEndTime = now + noteInfo.modRelease;
847
- filterNode.frequency
848
- .cancelScheduledValues(stopTime)
849
- .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
850
- bufferSource.stop(volEndTime);
842
+ const { noteNumber } = scheduledNote;
843
+ const promise = this.releaseNote(channelNumber, noteNumber, velocity);
844
+ promises.push(promise);
851
845
  }
852
846
  });
853
847
  });
848
+ return promises;
854
849
  }
855
- releaseSostenuto(channelNumber) {
856
- const now = this.audioContext.currentTime;
850
+ releaseSostenutoPedal(channelNumber, halfVelocity) {
851
+ const velocity = halfVelocity * 2;
857
852
  const channel = this.channels[channelNumber];
853
+ const promises = [];
858
854
  channel.sostenutoPedal = false;
859
855
  channel.sostenutoNotes.forEach((activeNote) => {
860
- const { gainNode, bufferSource, noteInfo } = activeNote;
861
- const fadeTime = noteInfo.volRelease;
862
- gainNode.gain.cancelScheduledValues(now);
863
- gainNode.gain.linearRampToValueAtTime(0, now + fadeTime);
864
- bufferSource.stop(now + fadeTime);
856
+ const { noteNumber } = activeNote;
857
+ const promise = this.releaseNote(channelNumber, noteNumber, velocity);
858
+ promises.push(promise);
865
859
  });
866
860
  channel.sostenutoNotes.clear();
861
+ return promises;
867
862
  }
868
863
  handleMIDIMessage(statusByte, data1, data2) {
869
864
  const channelNumber = omni ? 0 : statusByte & 0x0F;
@@ -873,8 +868,6 @@ export class MidyGM2 {
873
868
  return this.releaseNote(channelNumber, data1, data2);
874
869
  case 0x90:
875
870
  return this.noteOn(channelNumber, data1, data2);
876
- case 0xA0:
877
- return this.handlePolyphonicKeyPressure(channelNumber, data1, data2);
878
871
  case 0xB0:
879
872
  return this.handleControlChange(channelNumber, data1, data2);
880
873
  case 0xC0:
@@ -882,38 +875,48 @@ export class MidyGM2 {
882
875
  case 0xD0:
883
876
  return this.handleChannelPressure(channelNumber, data1);
884
877
  case 0xE0:
885
- return this.handlePitchBend(channelNumber, data1, data2);
878
+ return this.handlePitchBendMessage(channelNumber, data1, data2);
886
879
  default:
887
880
  console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
888
881
  }
889
882
  }
890
- handlePolyphonicKeyPressure(channelNumber, noteNumber, pressure) {
891
- const now = this.audioContext.currentTime;
892
- const channel = this.channels[channelNumber];
893
- const scheduledNotes = channel.scheduledNotes.get(noteNumber);
894
- pressure /= 127;
895
- if (scheduledNotes) {
896
- scheduledNotes.forEach((scheduledNote) => {
897
- if (scheduledNote) {
898
- const { initialAttenuation } = scheduledNote.noteInfo;
899
- const gain = this.cbToRatio(-initialAttenuation) * pressure;
900
- scheduledNote.gainNode.gain.cancelScheduledValues(now);
901
- scheduledNote.gainNode.gain.setValueAtTime(gain, now);
902
- }
903
- });
904
- }
905
- }
906
883
  handleProgramChange(channelNumber, program) {
907
884
  const channel = this.channels[channelNumber];
908
885
  channel.bank = channel.bankMSB * 128 + channel.bankLSB;
909
886
  channel.program = program;
910
887
  }
911
888
  handleChannelPressure(channelNumber, pressure) {
912
- this.channels[channelNumber].channelPressure = pressure;
889
+ const now = this.audioContext.currentTime;
890
+ const channel = this.channels[channelNumber];
891
+ pressure /= 64;
892
+ channel.channelPressure = pressure;
893
+ const activeNotes = this.getActiveNotes(channel);
894
+ if (channel.channelPressure.amplitudeControl !== 1) {
895
+ activeNotes.forEach((activeNote) => {
896
+ const gain = activeNote.gainNode.gain.value;
897
+ activeNote.gainNode.gain
898
+ .cancelScheduledValues(now)
899
+ .setValueAtTime(gain * pressure, now);
900
+ });
901
+ }
913
902
  }
914
- handlePitchBend(channelNumber, lsb, msb) {
915
- const pitchBend = (msb * 128 + lsb - 8192) / 8192;
916
- this.channels[channelNumber].pitchBend = pitchBend;
903
+ handlePitchBendMessage(channelNumber, lsb, msb) {
904
+ const pitchBend = msb * 128 + lsb;
905
+ this.handlePitchBend(channelNumber, pitchBend);
906
+ }
907
+ handlePitchBend(channelNumber, pitchBend) {
908
+ const now = this.audioContext.currentTime;
909
+ const channel = this.channels[channelNumber];
910
+ channel.pitchBend = (pitchBend - 8192) / 8192;
911
+ const semitoneOffset = this.calcSemitoneOffset(channel);
912
+ const activeNotes = this.getActiveNotes(channel);
913
+ activeNotes.forEach((activeNote) => {
914
+ const { bufferSource, noteInfo, noteNumber } = activeNote;
915
+ const playbackRate = calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
916
+ bufferSource.playbackRate
917
+ .cancelScheduledValues(now)
918
+ .setValueAtTime(playbackRate * pressure, now);
919
+ });
917
920
  }
918
921
  handleControlChange(channelNumber, controller, value) {
919
922
  switch (controller) {
@@ -973,13 +976,9 @@ export class MidyGM2 {
973
976
  this.channels[channelNumber].bankMSB = msb;
974
977
  }
975
978
  setModulation(channelNumber, modulation) {
976
- const now = this.audioContext.currentTime;
977
979
  const channel = this.channels[channelNumber];
978
- channel.modulation = (modulation * 100 / 127) *
979
- channel.modulationDepthRange;
980
- const lfoGain = channel.modulationEffect.lfoGain;
981
- lfoGain.gain.cancelScheduledValues(now);
982
- lfoGain.gain.setValueAtTime(channel.modulation, now);
980
+ channel.modulation = (modulation / 127) *
981
+ (channel.modulationDepthRange * 100);
983
982
  }
984
983
  setPortamentoTime(channelNumber, portamentoTime) {
985
984
  this.channels[channelNumber].portamentoTime = portamentoTime / 127;
@@ -1014,7 +1013,7 @@ export class MidyGM2 {
1014
1013
  const isOn = value >= 64;
1015
1014
  this.channels[channelNumber].sustainPedal = isOn;
1016
1015
  if (!isOn) {
1017
- this.releaseSustainPedal(channelNumber);
1016
+ this.releaseSustainPedal(channelNumber, value);
1018
1017
  }
1019
1018
  }
1020
1019
  setPortamento(channelNumber, value) {
@@ -1043,11 +1042,13 @@ export class MidyGM2 {
1043
1042
  const activeNotes = this.getActiveNotes(channel);
1044
1043
  channel.sostenutoNotes = new Map(activeNotes);
1045
1044
  }
1045
+ else {
1046
+ this.releaseSostenutoPedal(channelNumber, value);
1047
+ }
1046
1048
  }
1047
1049
  setSoftPedal(channelNumber, softPedal) {
1048
1050
  const channel = this.channels[channelNumber];
1049
1051
  channel.softPedal = softPedal / 127;
1050
- this.updateChannelGain(channel);
1051
1052
  }
1052
1053
  setRPNMSB(channelNumber, value) {
1053
1054
  this.channels[channelNumber].rpnMSB = value;
@@ -1188,10 +1189,10 @@ export class MidyGM2 {
1188
1189
  switch (data[3]) {
1189
1190
  // case 1:
1190
1191
  // // TODO
1191
- // return this.handleChannelPressure();
1192
+ // return this.setChannelPressure();
1192
1193
  // case 3:
1193
1194
  // // TODO
1194
- // return this.handleControlChange();
1195
+ // return this.setControlChange();
1195
1196
  default:
1196
1197
  console.warn(`Unsupported Exclusive Message ${data}`);
1197
1198
  }
@@ -1210,20 +1211,25 @@ export class MidyGM2 {
1210
1211
  }
1211
1212
  }
1212
1213
  handleMasterVolumeSysEx(data) {
1213
- const volume = (data[5] * 128 + data[4] - 8192) / 8192;
1214
+ const volume = (data[5] * 128 + data[4]) / 16383;
1214
1215
  this.handleMasterVolume(volume);
1215
1216
  }
1216
1217
  handleMasterVolume(volume) {
1217
- const now = this.audioContext.currentTime;
1218
- this.masterGain.gain.cancelScheduledValues(now);
1219
- this.masterGain.gain.setValueAtTime(volume * volume, now);
1218
+ if (volume < 0 && 1 < volume) {
1219
+ console.error("Master Volume is out of range");
1220
+ }
1221
+ else {
1222
+ const now = this.audioContext.currentTime;
1223
+ this.masterGain.gain.cancelScheduledValues(now);
1224
+ this.masterGain.gain.setValueAtTime(volume * volume, now);
1225
+ }
1220
1226
  }
1221
1227
  handleMasterFineTuningSysEx(data) {
1222
1228
  const fineTuning = (data[5] * 128 + data[4] - 8192) / 8192;
1223
1229
  this.handleMasterFineTuning(fineTuning);
1224
1230
  }
1225
1231
  handleMasterFineTuning(fineTuning) {
1226
- if (fineTuning < 0 && 1 < fineTuning) {
1232
+ if (fineTuning < -1 && 1 < fineTuning) {
1227
1233
  console.error("Master Fine Tuning value is out of range");
1228
1234
  }
1229
1235
  else {
@@ -1273,7 +1279,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
1273
1279
  writable: true,
1274
1280
  value: {
1275
1281
  currentBufferSource: null,
1276
- volume: 1,
1282
+ volume: 100 / 127,
1277
1283
  pan: 0,
1278
1284
  portamentoTime: 0,
1279
1285
  reverb: 0,
@@ -1290,7 +1296,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
1290
1296
  pitchBend: 0,
1291
1297
  fineTuning: 0,
1292
1298
  coarseTuning: 0,
1293
- modulationDepthRange: 2,
1299
+ modulationDepthRange: 0.5,
1294
1300
  }
1295
1301
  });
1296
1302
  Object.defineProperty(MidyGM2, "effectSettings", {
@@ -1310,3 +1316,16 @@ Object.defineProperty(MidyGM2, "effectSettings", {
1310
1316
  pitchBendRange: 2,
1311
1317
  }
1312
1318
  });
1319
+ Object.defineProperty(MidyGM2, "controllerDestinationSettings", {
1320
+ enumerable: true,
1321
+ configurable: true,
1322
+ writable: true,
1323
+ value: {
1324
+ pitchControl: 0,
1325
+ filterCutoffControl: 0,
1326
+ amplitudeControl: 1,
1327
+ lfoPitchDepth: 0,
1328
+ lfoFilterDepth: 0,
1329
+ lfoAmplitudeDepth: 0,
1330
+ }
1331
+ });
@@ -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"}